/*
	Copyright 2008 Jay Elliott

	This file is part of libemath.

	libemath is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	libemath is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with libemath.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __CORIENTEDBOX_H_
#define __CORIENTEDBOX_H_

#include <GL/gl.h>

#include "cPoint3d.h"
#include "cQuaternion.h"
#include "cMatrix.h"
#include "macros.h"


namespace emath
{

class cOrientedBox
{
private:
	cPoint3d pos;
	cQuaternion xRot, yRot, zRot;
	cPoint3d points[8];

	static void GetPoints(cPoint3d points[8], const cPoint3d& extent);
	
public:
	inline cOrientedBox(const cOrientedBox& other);//copy constructor
	inline cOrientedBox(const cPoint3d verts[8], const cPoint3d& loc);
	inline cOrientedBox(const cPoint3d& ext, const cPoint3d& loc);


	void GetPoints(cPoint3d PointBuffer[8]) const;
	void GetNormals(cPoint3d norms[6]) const;

	inline void translate(const cPoint3d& disp);

	inline void pitch(float deg);
	inline void yaw(float deg);
	inline void roll(float deg);

	bool intersects(const cOrientedBox& other) const;

	/*
		the box returned by this function is (usually) not centered around its origin

		it might be, but you shouldn't count on it

		I might be able to fix this by setting the origin to the average of all of the vertices
		in the returned box, then making all other points relative to that, but I haven't tried that yet
	*/
	static cOrientedBox CombineBoxes(const cOrientedBox& box1, const cOrientedBox& box2);
};



/*************************************
*
*
*	inline function definitions
*
*
***************************************/


cOrientedBox::cOrientedBox(const cOrientedBox& other)
{
	xRot = other.xRot;
	yRot = other.yRot;
	zRot = other.zRot;

	pos = other.pos;

	for (int i = 0; i < 8; i++)
		points[i] = other.points[i];
}

cOrientedBox::cOrientedBox(const cPoint3d verts[8], const cPoint3d& loc)
{
	pos = loc;

	for (int i = 0; i < 8; i++)
		points[i] = verts[i];
}

cOrientedBox::cOrientedBox(const cPoint3d& ext, const cPoint3d& loc) : xRot(0.0f, cPoint3d(1.0f, 0.0f, 0.0f)), yRot(0.0f, cPoint3d(0.0f, 1.0f, 0.0f)), zRot(0.0f, cPoint3d(0.0f, 0.0f, 1.0f))
{
	pos = loc;
	GetPoints(points, ext);
}

void cOrientedBox::pitch(float deg)
{
	xRot = xRot * cQuaternion(deg, cPoint3d(1.0f, 0.0f, 0.0f));

	xRot.normalize();
}

void cOrientedBox::yaw(float deg)
{
	yRot = yRot * cQuaternion(deg, cPoint3d(0.0f, 1.0f, 0.0f));

	yRot.normalize();
}

void cOrientedBox::roll(float deg)
{
	zRot = zRot * cQuaternion(deg, cPoint3d(0.0f, 0.0f, 1.0f));

	zRot.normalize();
}

void cOrientedBox::translate(const cPoint3d& disp)
{
	pos = pos + disp;
}

}

#endif
